<!DOCTYPE html>
<html lang="zh-CN">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>深入解析Spring AOP实现原理 | 技术小馆</title>
    <link href="https://cdn.staticfile.org/font-awesome/6.4.0/css/all.min.css" rel="stylesheet">
    <link href="https://cdn.staticfile.org/tailwindcss/2.2.19/tailwind.min.css" rel="stylesheet">
    <link href="https://fonts.googleapis.com/css2?family=Noto+Serif+SC:wght@400;500;600;700&family=Noto+Sans+SC:wght@300;400;500;700&display=swap" rel="stylesheet">
    <script src="https://cdn.jsdelivr.net/npm/mermaid@latest/dist/mermaid.min.js"></script>
    <style>
        body {
            font-family: 'Noto Sans SC', 'Noto Serif SC', Tahoma, Arial, Roboto, "Droid Sans", "Helvetica Neue", "Droid Sans Fallback", "Heiti SC", "Hiragino Sans GB", Simsun, sans-serif;
            color: #333;
            line-height: 1.6;
        }
        .hero-gradient {
            background: linear-gradient(135deg, #6e8efb 0%, #a777e3 100%);
        }
        .code-block {
            background: #282c34;
            border-radius: 8px;
            position: relative;
        }
        .code-block::before {
            content: '';
            position: absolute;
            top: 12px;
            left: 12px;
            width: 12px;
            height: 12px;
            border-radius: 50%;
            background: #ff5f56;
            box-shadow: 20px 0 0 #ffbd2e, 40px 0 0 #27c93f;
        }
        .card-hover:hover {
            transform: translateY(-5px);
            box-shadow: 0 20px 25px -5px rgba(0, 0, 0, 0.1), 0 10px 10px -5px rgba(0, 0, 0, 0.04);
        }
        .drop-cap::first-letter {
            float: left;
            font-size: 3.5em;
            line-height: 0.85;
            font-weight: bold;
            margin-right: 0.1em;
            color: #6e8efb;
        }
        .section-divider {
            position: relative;
            height: 1px;
            background: linear-gradient(90deg, transparent, rgba(0,0,0,0.1), transparent);
        }
        .section-divider::after {
            content: '';
            position: absolute;
            left: 50%;
            top: -5px;
            transform: translateX(-50%);
            width: 10px;
            height: 10px;
            border-radius: 50%;
            background: #6e8efb;
        }
    </style>
</head>
<body class="bg-gray-50">
    <!-- Hero Section -->
    <div class="hero-gradient text-white py-20 px-4 sm:px-6 lg:px-8">
        <div class="max-w-5xl mx-auto text-center">
            <h1 class="text-4xl md:text-5xl font-bold mb-4 tracking-tight">深入解析Spring AOP实现原理</h1>
            <p class="text-xl md:text-2xl font-light mb-8 opacity-90">从源码角度剖析面向切面编程的核心机制</p>
            <div class="flex justify-center space-x-4">
                <a href="#section1" class="px-6 py-2 bg-white text-indigo-600 font-medium rounded-full hover:bg-opacity-90 transition-all">开始阅读</a>
                <a href="#section6" class="px-6 py-2 bg-white bg-opacity-20 text-white font-medium rounded-full hover:bg-opacity-30 transition-all">直接看代理机制</a>
            </div>
        </div>
    </div>

    <!-- Main Content -->
    <div class="max-w-5xl mx-auto px-4 sm:px-6 lg:px-8 py-12">
        <!-- Introduction -->
        <div class="mb-16">
            <p class="drop-cap text-gray-700 text-lg leading-relaxed">为了深入分析 <span class="font-bold text-indigo-600">Spring AOP（面向切面编程）</span> 的实现，我们将从源码的角度，详细讲解它的各个核心部分和执行流程。本文将涵盖 Spring AOP 的基础原理、关键类的实现细节、代理机制、切面（Aspect）、连接点（JoinPoint）、通知（Advice）等重要概念，并通过具体源码展示如何实现这些功能。</p>
        </div>

        <!-- Section 1 -->
        <section id="section1" class="mb-20">
            <div class="flex items-center mb-6">
                <div class="w-10 h-10 rounded-full bg-indigo-100 text-indigo-600 flex items-center justify-center mr-4">
                    <span class="text-xl font-bold">1</span>
                </div>
                <h2 class="text-3xl font-bold text-gray-800">Spring AOP 的基础概念</h2>
            </div>
            <div class="pl-14">
                <p class="text-gray-700 mb-6">在讲解源码之前，我们先简要回顾一下 Spring AOP 的核心概念。</p>
                
                <div class="grid md:grid-cols-2 gap-6 mb-8">
                    <div class="bg-white p-6 rounded-xl shadow-sm border border-gray-100 card-hover transition-all duration-300">
                        <div class="flex items-center mb-3">
                            <div class="w-8 h-8 rounded-full bg-indigo-50 text-indigo-600 flex items-center justify-center mr-3">
                                <i class="fas fa-cut"></i>
                            </div>
                            <h3 class="text-xl font-semibold text-gray-800">切面（Aspect）</h3>
                        </div>
                        <p class="text-gray-600">切面是横切关注点的模块化。可以通过切面将日志、事务、性能监控等功能从业务逻辑中分离出来。</p>
                    </div>
                    
                    <div class="bg-white p-6 rounded-xl shadow-sm border border-gray-100 card-hover transition-all duration-300">
                        <div class="flex items-center mb-3">
                            <div class="w-8 h-8 rounded-full bg-purple-50 text-purple-600 flex items-center justify-center mr-3">
                                <i class="fas fa-link"></i>
                            </div>
                            <h3 class="text-xl font-semibold text-gray-800">连接点（JoinPoint）</h3>
                        </div>
                        <p class="text-gray-600">连接点是程序执行过程中能够插入切面的点，例如方法调用、方法执行等。</p>
                    </div>
                </div>

                <div class="grid md:grid-cols-3 gap-6">
                    <div class="bg-white p-6 rounded-xl shadow-sm border border-gray-100 card-hover transition-all duration-300">
                        <div class="flex items-center mb-3">
                            <div class="w-8 h-8 rounded-full bg-blue-50 text-blue-600 flex items-center justify-center mr-3">
                                <i class="fas fa-bell"></i>
                            </div>
                            <h3 class="text-xl font-semibold text-gray-800">通知（Advice）</h3>
                        </div>
                        <p class="text-gray-600">通知定义了切面在连接点的执行行为，例如前置通知、后置通知、异常通知等。</p>
                    </div>
                    
                    <div class="bg-white p-6 rounded-xl shadow-sm border border-gray-100 card-hover transition-all duration-300">
                        <div class="flex items-center mb-3">
                            <div class="w-8 h-8 rounded-full bg-green-50 text-green-600 flex items-center justify-center mr-3">
                                <i class="fas fa-bullseye"></i>
                            </div>
                            <h3 class="text-xl font-semibold text-gray-800">切入点（Pointcut）</h3>
                        </div>
                        <p class="text-gray-600">切入点是通知应用的具体位置，通常是方法调用的位置。</p>
                    </div>
                    
                    <div class="bg-white p-6 rounded-xl shadow-sm border border-gray-100 card-hover transition-all duration-300">
                        <div class="flex items-center mb-3">
                            <div class="w-8 h-8 rounded-full bg-red-50 text-red-600 flex items-center justify-center mr-3">
                                <i class="fas fa-user-secret"></i>
                            </div>
                            <h3 class="text-xl font-semibold text-gray-800">代理（Proxy）</h3>
                        </div>
                        <p class="text-gray-600">Spring AOP 是基于代理实现的。它通过代理对象来增强目标对象的功能。</p>
                    </div>
                </div>
            </div>
        </section>

        <!-- Visual Diagram -->
        <div class="my-16 p-8 bg-white rounded-xl shadow-sm border border-gray-100">
            <h3 class="text-2xl font-bold text-center mb-8 text-gray-800">Spring AOP 核心概念关系图</h3>
            <div class="mermaid">
                graph TD
                    A[Aspect 切面] -->|包含| B[Advice 通知]
                    A -->|包含| C[Pointcut 切入点]
                    B -->|作用于| D[JoinPoint 连接点]
                    C -->|匹配| D
                    E[Proxy 代理] -->|增强| F[Target 目标对象]
                    E -->|实现| G[JDK动态代理]
                    E -->|实现| H[CGLIB代理]
            </div>
        </div>

        <!-- Section 2 -->
        <section id="section2" class="mb-20">
            <div class="flex items-center mb-6">
                <div class="w-10 h-10 rounded-full bg-indigo-100 text-indigo-600 flex items-center justify-center mr-4">
                    <span class="text-xl font-bold">2</span>
                </div>
                <h2 class="text-3xl font-bold text-gray-800">AOP 的实现方式：代理模式</h2>
            </div>
            <div class="pl-14">
                <p class="text-gray-700 mb-6">Spring AOP 主要通过代理模式来实现横切关注点的插入。Spring 提供了两种类型的代理：</p>
                
                <div class="grid md:grid-cols-2 gap-8 mb-8">
                    <div>
                        <h3 class="text-xl font-semibold mb-4 text-gray-800 flex items-center">
                            <span class="w-6 h-6 bg-blue-100 text-blue-600 rounded-full flex items-center justify-center mr-2">
                                <i class="fas fa-code text-sm"></i>
                            </span>
                            JDK 动态代理
                        </h3>
                        <p class="text-gray-600 mb-4">为接口创建代理类，适用于目标对象实现了接口的情况。</p>
                        <div class="code-block p-4 text-gray-200 text-sm overflow-x-auto">
                            <pre><code>public class JdkDynamicAopProxy implements InvocationHandler {
    private final Object target;
    private final AdvisedSupport advised;

    public JdkDynamicAopProxy(AdvisedSupport advised) {
        this.advised = advised;
        this.target = advised.getTargetSource().getTarget();
    }

    @Override
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
        MethodInvocation invocation = new ReflectiveMethodInvocation(target, method, args);
        return advised.getInterceptorChain().invoke(invocation);
    }
}</code></pre>
                        </div>
                        <p class="text-gray-600 mt-4 text-sm"><span class="font-medium">关键点：</span> <code>JdkDynamicAopProxy</code> 实现了 <code>InvocationHandler</code> 接口，通过反射机制将目标方法的调用委托给 <code>invoke()</code> 方法。</p>
                    </div>
                    
                    <div>
                        <h3 class="text-xl font-semibold mb-4 text-gray-800 flex items-center">
                            <span class="w-6 h-6 bg-purple-100 text-purple-600 rounded-full flex items-center justify-center mr-2">
                                <i class="fas fa-project-diagram text-sm"></i>
                            </span>
                            CGLIB 代理
                        </h3>
                        <p class="text-gray-600 mb-4">对于没有实现接口的类，Spring 使用 CGLIB 代理。通过 CGLIB，Spring 会创建目标类的子类，并通过子类来增强方法。</p>
                        <div class="code-block p-4 text-gray-200 text-sm overflow-x-auto">
                            <pre><code>public class CglibAopProxy implements AopProxy {
    private final AdvisedSupport advised;

    public CglibAopProxy(AdvisedSupport advised) {
        this.advised = advised;
    }

    @Override
    public Object getProxy(ClassLoader classLoader) {
        Enhancer enhancer = new Enhancer();
        enhancer.setSuperclass(advised.getTargetSource().getTargetClass());
        enhancer.setCallback(new AopInterceptor());
        return enhancer.create();
    }
}</code></pre>
                        </div>
                        <p class="text-gray-600 mt-4 text-sm"><span class="font-medium">关键点：</span> <code>Enhancer</code> 是 CGLIB 的核心类，通过它创建目标对象的代理子类。</p>
                    </div>
                </div>
            </div>
        </section>

        <div class="section-divider my-16"></div>

        <!-- Section 3 -->
        <section id="section3" class="mb-20">
            <div class="flex items-center mb-6">
                <div class="w-10 h-10 rounded-full bg-indigo-100 text-indigo-600 flex items-center justify-center mr-4">
                    <span class="text-xl font-bold">3</span>
                </div>
                <h2 class="text-3xl font-bold text-gray-800">核心类：AdvisedSupport 和 TargetSource</h2>
            </div>
            <div class="pl-14">
                <div class="grid md:grid-cols-2 gap-8">
                    <div>
                        <h3 class="text-xl font-semibold mb-4 text-gray-800 flex items-center">
                            <span class="w-6 h-6 bg-indigo-100 text-indigo-600 rounded-full flex items-center justify-center mr-2">
                                <i class="fas fa-cogs text-sm"></i>
                            </span>
                            AdvisedSupport
                        </h3>
                        <p class="text-gray-600 mb-4">是 Spring AOP 配置和支持的核心类，包含了目标对象、增强器（Advice）和切入点（Pointcut）等信息。</p>
                        <div class="code-block p-4 text-gray-200 text-sm overflow-x-auto">
                            <pre><code>public class AdvisedSupport {
    private Object target;  // 目标对象
    private List&lt;Advisor&gt; advisors;  // 增强器集合
    private TargetSource targetSource;  // 目标来源

    public Object getTarget() {
        return target;
    }

    public List&lt;Advisor&gt; getAdvisors() {
        return advisors;
    }

    public TargetSource getTargetSource() {
        return targetSource;
    }
}</code></pre>
                        </div>
                    </div>
                    
                    <div>
                        <h3 class="text-xl font-semibold mb-4 text-gray-800 flex items-center">
                            <span class="w-6 h-6 bg-blue-100 text-blue-600 rounded-full flex items-center justify-center mr-2">
                                <i class="fas fa-bullseye text-sm"></i>
                            </span>
                            TargetSource
                        </h3>
                        <p class="text-gray-600 mb-4">用来获取目标对象。常见实现有 <code>SingletonTargetSource</code>、<code>PrototypeTargetSource</code> 等。</p>
                        <div class="code-block p-4 text-gray-200 text-sm overflow-x-auto">
                            <pre><code>public interface TargetSource {
    Object getTarget();
    Class&lt;?&gt; getTargetClass();
    boolean isStatic();
}</code></pre>
                        </div>
                    </div>
                </div>
            </div>
        </section>

        <!-- Section 4 -->
        <section id="section4" class="mb-20">
            <div class="flex items-center mb-6">
                <div class="w-10 h-10 rounded-full bg-indigo-100 text-indigo-600 flex items-center justify-center mr-4">
                    <span class="text-xl font-bold">4</span>
                </div>
                <h2 class="text-3xl font-bold text-gray-800">Spring AOP 切面（Aspect）的实现</h2>
            </div>
            <div class="pl-14">
                <div class="grid md:grid-cols-2 gap-8">
                    <div>
                        <h3 class="text-xl font-semibold mb-4 text-gray-800 flex items-center">
                            <span class="w-6 h-6 bg-purple-100 text-purple-600 rounded-full flex items-center justify-center mr-2">
                                <i class="fas fa-at text-sm"></i>
                            </span>
                            AspectJ 切面与注解方式
                        </h3>
                        <p class="text-gray-600 mb-4">Spring AOP 提供了与 AspectJ 的集成，默认支持使用注解方式定义切面。</p>
                        <div class="code-block p-4 text-gray-200 text-sm overflow-x-auto">
                            <pre><code>@Aspect
public class MyAspect {
    @Before("execution(* com.example.service.*.*(..))")
    public void beforeMethod(JoinPoint joinPoint) {
        System.out.println("Before method: " + joinPoint.getSignature());
    }
}</code></pre>
                        </div>
                    </div>
                    
                    <div>
                        <h3 class="text-xl font-semibold mb-4 text-gray-800 flex items-center">
                            <span class="w-6 h-6 bg-green-100 text-green-600 rounded-full flex items-center justify-center mr-2">
                                <i class="fas fa-expand text-sm"></i>
                            </span>
                            AspectJ Expression
                        </h3>
                        <p class="text-gray-600 mb-4">AspectJ 的切入点表达式非常强大，可以根据方法签名、注解等条件定义切入点。</p>
                        <div class="code-block p-4 text-gray-200 text-sm overflow-x-auto">
                            <pre><code>@Around("execution(* com.example.service.*.*(..))")
public Object aroundMethod(ProceedingJoinPoint joinPoint) throws Throwable {
    System.out.println("Around method: " + joinPoint.getSignature());
    return joinPoint.proceed();  // 执行目标方法
}</code></pre>
                        </div>
                    </div>
                </div>
            </div>
        </section>

        <!-- Section 5 -->
        <section id="section5" class="mb-20">
            <div class="flex items-center mb-6">
                <div class="w-10 h-10 rounded-full bg-indigo-100 text-indigo-600 flex items-center justify-center mr-4">
                    <span class="text-xl font-bold">5</span>
                </div>
                <h2 class="text-3xl font-bold text-gray-800">通知（Advice）的类型与实现</h2>
            </div>
            <div class="pl-14">
                <div class="grid md:grid-cols-2 gap-6 mb-8">
                    <div class="bg-white p-6 rounded-xl shadow-sm border border-gray-100">
                        <h3 class="text-lg font-semibold mb-3 text-gray-800 flex items-center">
                            <i class="fas fa-arrow-circle-up text-blue-500 mr-2"></i>
                            前置通知（Before）
                        </h3>
                        <div class="code-block p-4 text-gray-200 text-sm overflow-x-auto">
                            <pre><code>@Before("execution(* com.example.service.*.*(..))")
public void before(JoinPoint joinPoint) {
    System.out.println("Before method: " + joinPoint.getSignature());
}</code></pre>
                        </div>
                    </div>
                    
                    <div class="bg-white p-6 rounded-xl shadow-sm border border-gray-100">
                        <h3 class="text-lg font-semibold mb-3 text-gray-800 flex items-center">
                            <i class="fas fa-arrow-circle-down text-purple-500 mr-2"></i>
                            后置通知（After）
                        </h3>
                        <div class="code-block p-4 text-gray-200 text-sm overflow-x-auto">
                            <pre><code>@After("execution(* com.example.service.*.*(..))")
public void after(JoinPoint joinPoint) {
    System.out.println("After method: " + joinPoint.getSignature());
}</code></pre>
                        </div>
                    </div>
                </div>
                
                <div class="grid md:grid-cols-3 gap-6">
                    <div class="bg-white p-6 rounded-xl shadow-sm border border-gray-100">
                        <h3 class="text-lg font-semibold mb-3 text-gray-800 flex items-center">
                            <i class="fas fa-check-circle text-green-500 mr-2"></i>
                            返回通知（AfterReturning）
                        </h3>
                        <div class="code-block p-4 text-gray-200 text-sm overflow-x-auto">
                            <pre><code>@AfterReturning(pointcut = "execution(* com.example.service.*.*(..))", 
                returning = "result")
public void afterReturning(JoinPoint joinPoint, Object result) {
    System.out.println("AfterReturning method: " + joinPoint.getSignature() 
        + ", result: " + result);
}</code></pre>
                        </div>
                    </div>
                    
                    <div class="bg-white p-6 rounded-xl shadow-sm border border-gray-100">
                        <h3 class="text-lg font-semibold mb-3 text-gray-800 flex items-center">
                            <i class="fas fa-exclamation-circle text-red-500 mr-2"></i>
                            异常通知（AfterThrowing）
                        </h3>
                        <div class="code-block p-4 text-gray-200 text-sm overflow-x-auto">
                            <pre><code>@AfterThrowing(pointcut = "execution(* com.example.service.*.*(..))", 
                throwing = "ex")
public void afterThrowing(JoinPoint joinPoint, Exception ex) {
    System.out.println("AfterThrowing method: " + joinPoint.getSignature() 
        + ", exception: " + ex.getMessage());
}</code></pre>
                        </div>
                    </div>
                    
                    <div class="bg-white p-6 rounded-xl shadow-sm border border-gray-100">
                        <h3 class="text-lg font-semibold mb-3 text-gray-800 flex items-center">
                            <i class="fas fa-sync-alt text-yellow-500 mr-2"></i>
                            环绕通知（Around）
                        </h3>
                        <div class="code-block p-4 text-gray-200 text-sm overflow-x-auto">
                            <pre><code>@Around("execution(* com.example.service.*.*(..))")
public Object aroundMethod(ProceedingJoinPoint joinPoint) throws Throwable {
    System.out.println("Around before: " + joinPoint.getSignature());
    Object result = joinPoint.proceed();
    System.out.println("Around after: " + joinPoint.getSignature());
    return result;
}</code></pre>
                        </div>
                    </div>
                </div>
            </div>
        </section>

        <!-- Section 6 -->
        <section id="section6" class="mb-20">
            <div class="flex items-center mb-6">
                <div class="w-10 h-10 rounded-full bg-indigo-100 text-indigo-600 flex items-center justify-center mr-4">
                    <span class="text-xl font-bold">6</span>
                </div>
                <h2 class="text-3xl font-bold text-gray-800">Spring AOP 代理与增强机制</h2>
            </div>
            <div class="pl-14">
                <div class="grid md:grid-cols-2 gap-8">
                    <div>
                        <h3 class="text-xl font-semibold mb-4 text-gray-800 flex items-center">
                            <span class="w-6 h-6 bg-indigo-100 text-indigo-600 rounded-full flex items-center justify-center mr-2">
                                <i class="fas fa-plus-circle text-sm"></i>
                            </span>
                            AOP 代理的创建
                        </h3>
                        <p class="text-gray-600 mb-4">Spring 通过 <code>AopProxyFactory</code> 来选择合适的代理类型（JDK 动态代理或 CGLIB 代理）。</p>
                        <div class="code-block p-4 text-gray-200 text-sm overflow-x-auto">
                            <pre><code>public AopProxy createAopProxy(AdvisedSupport config) {
    if (config.getTargetSource().isStatic()) {
        return new JdkDynamicAopProxy(config);
    } else {
        return new CglibAopProxy(config);
    }
}</code></pre>
                        </div>
                    </div>
                    
                    <div>
                        <h3 class="text-xl font-semibold mb-4 text-gray-800 flex items-center">
                            <span class="w-6 h-6 bg-purple-100 text-purple-600 rounded-full flex items-center justify-center mr-2">
                                <i class="fas fa-shield-alt text-sm"></i>
                            </span>
                            增强器（Advisor）的实现
                        </h3>
                        <p class="text-gray-600 mb-4">增强器是 AOP 中定义通知和切入点的对象。</p>
                        <div class="code-block p-4 text-gray-200 text-sm overflow-x-auto">
                            <pre><code>public class MyAdvisor implements Advisor {
    private Advice advice;
    private Pointcut pointcut;

    public MyAdvisor(Advice advice, Pointcut pointcut) {
        this.advice = advice;
        this.pointcut = pointcut;
    }

    public Advice getAdvice() {
        return this.advice;
    }

    public Pointcut getPointcut() {
        return this.pointcut;
    }
}</code></pre>
                        </div>
                    </div>
                </div>
            </div>
        </section>

        <!-- Summary -->
        <div class="bg-indigo-50 rounded-xl p-8 mb-16">
            <h3 class="text-2xl font-bold mb-4 text-indigo-800 flex items-center">
                <i class="fas fa-lightbulb text-yellow-500 mr-2"></i>
                核心要点总结
            </h3>
            <ul class="space-y-3 text-gray-700">
                <li class="flex items-start">
                    <span class="text-indigo-600 mr-2 mt-1">•</span>
                    <span>Spring AOP 基于代理模式实现，支持 JDK 动态代理和 CGLIB 代理两种方式</span>
                </li>
                <li class="flex items-start">
                    <span class="text-indigo-600 mr-2 mt-1">•</span>
                    <span><code>AdvisedSupport</code> 是配置 AOP 代理的核心类，包含目标对象和增强器信息</span>
                </li>
                <li class="flex items-start">
                    <span class="text-indigo-600 mr-2 mt-1">•</span>
                    <span>切面通过 <code>@Aspect</code> 注解定义，可包含多种通知类型（Before/After/Around等）</span>
                </li>
                <li class="flex items-start">
                    <span class="text-indigo-600 mr-2 mt-1">•</span>
                    <span>AOP 代理在运行时动态生成，通过拦截方法调用实现横切关注点</span>
                </li>
                <li class="flex items-start">
                    <span class="text-indigo-600 mr-2 mt-1">•</span>
                    <span>切入点表达式（Pointcut）精确控制通知的应用位置</span>
                </li>
            </ul>
        </div>
    </div>

    <!-- Footer -->
    <footer class="bg-gray-900 text-gray-300 py-8">
        <div class="max-w-5xl mx-auto px-4 sm:px-6 lg:px-8">
            <div class="flex flex-col md:flex-row justify-between items-center">
                <div class="mb-4 md:mb-0">
                    <h3 class="text-xl font-bold text-white mb-1">技术小馆</h3>
                    <p class="text-gray-400">专注于技术原理深度解析</p>
                </div>
                <div>
                    <a href="http://www.yuque.com/jtostring" class="text-gray-300 hover:text-white transition-colors duration-200 flex items-center">
                        <i class="fas fa-globe mr-2"></i>
                        <span>http://www.yuque.com/jtostring</span>
                    </a>
                </div>
            </div>
        </div>
    </footer>

    <script>
        mermaid.initialize({
            startOnLoad: true,
            theme: 'default',
            flowchart: {
                useMaxWidth: true,
                htmlLabels: true,
                curve: 'basis'
            }
        });
    </script>
</body>
</html>